package jmine.tec.aom.services;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import jmine.tec.aom.builder.PropertyBuilder;
import jmine.tec.aom.builder.PropertyTypeBuilder;
import jmine.tec.aom.domain.AbstractPropertyValue;
import jmine.tec.aom.domain.Propertized;
import jmine.tec.aom.domain.Property;
import jmine.tec.aom.domain.PropertyType;
import jmine.tec.aom.domain.impl.AbstractPropertized;
import jmine.tec.aom.domain.impl.DoublePropertyValue;
import jmine.tec.aom.util.BasePropertyHandler;
import jmine.tec.aom.util.PropertyValueUtils;
import jmine.tec.services.api.ServiceExecutionException;
import jmine.tec.test.junit4.DBEnv;
import jmine.tec.test.junit4.DBTestCase;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
 * @author jrenaut
 */
@DBEnv(refdb = "jmine-tec-aom-db-test.xml", spring = "jmine-tec-aom-test.xml")
public class AbstractPropertyValueServiceShould extends DBTestCase {

    private Property p1;

    private Property p2;

    private AbstractPropertyValueService service;

    private Propertized p;

    @Before
    public void before() {
        this.p1 = PropertyBuilder.aProperty().withMnemonic("mne1").save();
        this.p2 = PropertyBuilder.aProperty().withMnemonic("mne2").save();
        this.service = new AbstractPropertyValueService() {
        };
        this.service.setPropertyValueUtils(DBTestCase.getBean(PropertyValueUtils.class));

        this.p = new AbstractPropertized() {
            @Override
            protected Propertized doGetPropertyHandler() {
                return new BasePropertyHandler(new HashSet<Property>(Arrays.asList(AbstractPropertyValueServiceShould.this.p1,
                        AbstractPropertyValueServiceShould.this.p2)), new HashSet<AbstractPropertyValue<?>>());
            }
        };

    }

    @Test
    public void handleAnEmptyPropertyValuesMap() throws ServiceExecutionException {
        this.service.setPropertyValues(new HashMap<String, String>());

        Assert.assertTrue(this.p.getPropertyValues().isEmpty());
        this.service.addPropertyValues(this.p, "identification");
        Assert.assertTrue(this.p.getPropertyValues().isEmpty());
    }

    @Test
    public void ignoreNullEntriesInMap() throws ServiceExecutionException {
        Map<String, String> values = new HashMap<String, String>();
        values.put("mne1", "val1");
        values.put("mne2", null);
        this.service.setPropertyValues(values);

        Assert.assertTrue(this.p.getPropertyValues().isEmpty());
        this.service.addPropertyValues(this.p, "identification");
        Assert.assertFalse(this.p.getPropertyValues().isEmpty());

        Assert.assertEquals(1, this.p.getPropertyValues().size());
    }

    @Test(expected = ServiceExecutionException.class)
    public void throwExceptionOnUnknownProperty() throws ServiceExecutionException {
        Map<String, String> values = new HashMap<String, String>();
        values.put("does_not_exist", "val");
        this.service.setPropertyValues(values);

        this.service.addPropertyValues(this.p, "identification");
    }

    @Test(expected = ServiceExecutionException.class)
    public void throwExceptionOnInvalidValue() throws ServiceExecutionException {
        PropertyType pt = PropertyTypeBuilder.aPropertyType().withMnemonic("double").withValueClass(DoublePropertyValue.class).save();
        final Property pdbl = PropertyBuilder.aProperty().withMnemonic("pdbl").withPropertyType(pt).save();

        this.p = new AbstractPropertized() {
            @Override
            protected Propertized doGetPropertyHandler() {
                return new BasePropertyHandler(new HashSet<Property>(Arrays.asList(pdbl)), new HashSet<AbstractPropertyValue<?>>());
            }
        };

        Map<String, String> values = new HashMap<String, String>();
        values.put("pdbl", "invalid_double");
        this.service.setPropertyValues(values);

        this.service.addPropertyValues(this.p, "identification");
    }

    @Test
    public void addPropertyValuesToAPropertized() throws ServiceExecutionException {
        Map<String, String> values = new HashMap<String, String>();
        values.put("mne1", "val1");
        values.put("mne2", "val2");
        this.service.setPropertyValues(values);

        Assert.assertTrue(this.p.getPropertyValues().isEmpty());
        this.service.addPropertyValues(this.p, "identification");
        Assert.assertFalse(this.p.getPropertyValues().isEmpty());

        Assert.assertEquals(2, this.p.getPropertyValues().size());

        AbstractPropertyValue pv1 = this.p.getPropertyValue(this.p1);
        Assert.assertNotNull(pv1);
        Assert.assertEquals("val1", pv1.getValueAsString());

        AbstractPropertyValue pv2 = this.p.getPropertyValue(this.p2);
        Assert.assertNotNull(pv2);
        Assert.assertEquals("val2", pv2.getValueAsString());
    }
}
